package com.suntop.carousel.qlmediaplay.danmu;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;

import com.suntop.carousel.R;
import com.suntop.carousel.qlmediaplay.bean.DamInfo;
import com.suntop.carousel.qlmediaplay.bean.Damma;


import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Random;

import androidx.annotation.FloatRange;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.widget.AppCompatTextView;

@SuppressLint("NewApi")
public class DanmakuView extends FrameLayout {
    private int withView = 0;
    private int heightView = 0;
    private int maxLine = 2;
    private float ratio = 1.0f;
    private float speed = 1.0f;
    private int time = 0;
    private RequestOptions requestOptions;
    private int dexRow;
    private boolean isCancel;
    private ArrayList<DamInfo> damInfos = new ArrayList<>();
    private ArrayList<Integer> dexList = new ArrayList<>();
    private ArrayList<Damma> arrayList = new ArrayList<>();
    private DanmaFinishListener danmaFinishListener;

    public DanmakuView(Context context) {
        super(context);
    }

    public DanmakuView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public DanmakuView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        withView = MeasureSpec.getSize(widthMeasureSpec);
        heightView = MeasureSpec.getSize(heightMeasureSpec);
        initDate();
    }

    private void initDate() {
        if (requestOptions == null)
            requestOptions = new RequestOptions()
                    .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
                    .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
                    .skipMemoryCache(true)
                    .dontTransform()
                    .circleCrop()
                    .error(R.drawable.empty_info);
        maxLine = (int) (heightView * (ratio) / (60 + 10));
        for (int i = 0; i < maxLine; i++) {
            dexList.add(i, withView);
        }
    }

    public DanmakuView setRatio(@FloatRange(from = 0.1f, to = 1.0f) float ratio) {
        this.ratio = ratio;
        maxLine = (int) (heightView * (ratio) / (60 + 10));
        dexList.clear();
        for (int i = 0; i < maxLine; i++) {
            dexList.add(i, withView);
        }
        return this;
    }

    public DanmakuView setSpeed(@FloatRange(from = 0.1f, to = 2.0f) float speed) {
        this.speed = speed;
        return this;
    }

    public DanmakuView setTime(@IntRange(from = 0, to = 20) int time) {
        this.time = time;
        return this;
    }

    public DanmakuView addDanmaFinishListener(DanmaFinishListener listener){
        this.danmaFinishListener=listener;
        return this;
    }

    public void setCancel(boolean cancel) {
        isCancel = cancel;
    }

    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case 1:
                    if (arrayList.size() == 0) {
                        //弹幕发送完成
                        if (danmaFinishListener!=null){
                            danmaFinishListener.finishPlay();
                        }
                        break;
                    }
                    initAnmintView(arrayList.get(0));
                    handler.sendEmptyMessageDelayed(1, 120);
                    break;
            }
            return false;
        }
    });


    @SuppressLint({"RestrictedApi", "InlinedApi"})
    private void initAnmintView(Damma damma) {
        View inflate = getItemView(damma);
        SoftReference<View> softReference = new SoftReference<>(inflate);
        int w = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        int h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        inflate.measure(w, h);
        final int itemWidth = inflate.getMeasuredWidth();
        final int itemHeight = inflate.getMeasuredHeight();
        DamInfo damInfo = takeTopForView(itemHeight, itemWidth);
        if (damInfo.getTop() == 0) {
            return;
        }
        if (arrayList.size() > 0) {
            arrayList.remove(damma);
        }
        damInfo.setLeft(withView);
        damInfo.setRight(withView + itemWidth);
        damInfo.setBottom(damInfo.getTop() + itemHeight);
        damInfos.add(damInfo);
        MyTranslateAnimation animation =
                new MyTranslateAnimation(withView, -itemWidth, damInfo.getTop()
                        , damInfo.getTop());
        animation.setUpDateListener(new TranslateAnimationListener() {
            @Override
            public void onAnimationUpdate(int tag, float dx, float dy) {
                if (isCancel) {
                    animation.cancel();
                    softReference.get().clearAnimation();
                    DanmakuView.this.removeView(softReference.get());
                    softReference.clear();
                }
                damInfo.setDex((int) (withView - (dx + itemWidth)));
                damInfo.setLeft((int) dx);
                damInfo.setRight((int) (dx + itemWidth));
                int line = damInfo.getLine();
                dexList.set(line, damInfo.getDex());
            }
        });
        animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                animation.cancel();
                DanmakuView.this.removeView(softReference.get());
                softReference.clear();
                damInfos.remove(damInfo);
                dexList.set(damInfo.getLine(), withView);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        animation.setTag(damInfo.getIdDex());
        animation.setFillAfter(true);
        animation.setRepeatCount(0);
        animation.setInterpolator(new LinearInterpolator());
        animation.setRepeatMode(Animation.RESTART);
        if (time == 0) {
            int delay = (int) (takeDuration(itemWidth) * speed);
            animation.setDuration(delay);
        } else {
            animation.setDuration(time * 1000);
        }
        addView(softReference.get(), itemWidth, itemHeight);
        inflate.startAnimation(animation);

    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    @SuppressLint("RestrictedApi")
    private View getItemView(Damma damma) {
        View inflate = LayoutInflater.from(getContext())
                .inflate(R.layout.damma_layout_item, null);
        ImageView imageView = inflate.findViewById(R.id.img_danma_icon);
        AppCompatTextView textViewName = inflate.findViewById(R.id.txt_danma_name);
        View rlyDanma = inflate.findViewById(R.id.rly_danma);
        View llyDanma = inflate.findViewById(R.id.lly_danma);
        AppCompatTextView textViewComment = inflate.findViewById(R.id.txt_danma_comment);
        if (!TextUtils.isEmpty(damma.getBackground())) {
            if (damma.getBackground().matches("^[0-9]+$")) {
                inflate.setBackgroundResource(Integer.parseInt(damma.getBackground()));
            } else if (damma.getBackground().matches("^#[0-9A-Fa-f]+$")) {
                inflate.setBackgroundColor(Color.parseColor(damma.getBackground()));
            } else {
                Glide.with(this).asBitmap().load(damma.getBackground())
                        .apply(requestOptions)
                        .addListener(new RequestListener<Bitmap>() {
                            @Override
                            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                                return false;
                            }

                            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
                            @Override
                            public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                                if (resource != null && isFirstResource) {
                                    inflate.setBackground(new BitmapDrawable(resource));
                                }
                                return false;
                            }
                        }).submit();
            }

        }
        if (!TextUtils.isEmpty(damma.getIcon())) {
            if (damma.getIcon().matches("^[0-9A-Fa-f]+$")) {
                int icon = Integer.parseInt(damma.getIcon());
                Glide.with(this).load(icon)
                        .apply(requestOptions)
                        .into(imageView);
            } else {
                Glide.with(this).load(damma.getIcon())
                        .apply(requestOptions)
                        .into(imageView);
            }
        } else {
            rlyDanma.setVisibility(GONE);
        }
        if (TextUtils.isEmpty(damma.getName())) {
            textViewName.setVisibility(GONE);
        } else {
            textViewName.setText(damma.getName());
            textViewName.setTextColor(Color.GREEN);
            if (!TextUtils.isEmpty(damma.getNameColor())) {
                if (damma.getNameColor().matches("^[0-9]+$")) {
                    textViewName.setTextColor(Integer.parseInt(damma.getNameColor()));
                } else if (damma.getNameColor().matches("^#[0-9A-Fa-f]{8}$")) {
                    textViewName.setTextColor(Color.parseColor(damma.getNameColor()));
                }
            }
        }
        if (damma.getMaxSize() != 0 && damma.getMinSize() != 0) {
            textViewComment.setAutoSizeTextTypeUniformWithConfiguration(
                    damma.getMinSize(), damma.getMaxSize(), 1
                    , TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM);
            textViewName.setAutoSizeTextTypeUniformWithConfiguration(
                    damma.getMinSize() + 10, damma.getMaxSize() + 10, 1
                    , TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM
            );
        } else {
            textViewName.setTextSize(30);
            textViewComment.setTextSize(26);
        }
        if (TextUtils.isEmpty(damma.getText())) {
            textViewComment.setVisibility(GONE);
        } else {
            if (damma.isHtml()) {
                Spanned spanned = Html.fromHtml(damma.getText());
                textViewComment.setText(spanned);
            } else {
                textViewComment.setText(damma.getText());
                if (damma.getTextColor().matches("^[0-9]+$")) {
                    textViewComment.setTextColor(Integer.parseInt(damma.getTextColor()));
                } else if (damma.getTextColor().matches("^#[0-9A-Fa-f]{8}$")) {
                    textViewComment.setTextColor(Color.parseColor(damma.getTextColor()));
                } else {
                    textViewComment.setTextColor(Color.WHITE);
                }
                if (damma.getColorStart() != 0 || damma.getColorCenter() != 0 || damma.getColorEnd() != 0) {
                    SpannableStringBuilder ramRadiusStringBuilder = getRamRadiusStringBuilder(damma.getText(), damma.getColorStart()
                            , damma.getColorCenter(), damma.getColorEnd());
                    textViewComment.setText(ramRadiusStringBuilder);
                }
                if (damma.isRoam()) {
                    Random random = new Random();
                    SpannableStringBuilder ramRadiusStringBuilder
                            = getRamRadiusStringBuilder(damma.getText(), Color.rgb(random.nextInt(255)
                            , random.nextInt(255), random.nextInt(255))
                            , Color.rgb(random.nextInt(255)
                                    , random.nextInt(255), random.nextInt(255)), Color.rgb(random.nextInt(255)
                                    , random.nextInt(255), random.nextInt(255)));
                    textViewComment.setText(ramRadiusStringBuilder);
                }
            }
        }
        int direction = damma.getDirection();
        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) llyDanma.getLayoutParams();
        if (direction == 0) {
            layoutParams.setLayoutDirection(LinearLayout.HORIZONTAL);
        } else {
            layoutParams.setLayoutDirection(LinearLayout.VERTICAL);
        }
        llyDanma.setLayoutParams(layoutParams);
        return inflate;
    }

    private int takeDuration(int itemWidth) {
        int i = (withView + 2 * itemWidth) / 120;
        int i1 = (withView + 2 * itemWidth) % 120 > 0 ? 1 : 0;
        return (i + i1) * 1000;
    }

    public void setArrayList(ArrayList<Damma> arrayList) {
        this.arrayList.clear();
        isCancel = false;
        this.arrayList.addAll(arrayList);
    }

    public void addDamma(Damma damma) {
        this.arrayList.add(0, damma);
        if (!handler.hasMessages(1)) {
            handler.sendEmptyMessage(1);
        }
    }

    public void startPlay() {
        if (handler.hasMessages(1)) {
            handler.removeMessages(1);
        }
        handler.sendEmptyMessageDelayed(1, 100);
    }

    public void pausePlay() {
        if (handler.hasMessages(1)) {
            handler.removeMessages(1);
        }
    }

    public void stopPlay() {
        if (handler.hasMessages(1)) {
            handler.removeMessages(1);
        }
        isCancel = true;
        arrayList.clear();
    }


    private DamInfo takeTopForView(int itemHeight, int itemWith) {
        int size = dexList.size();
        DamInfo damInfo = new DamInfo();
        damInfo.setIdDex(dexRow);
        dexRow++;
        if (dexRow >= Integer.MAX_VALUE) {
            dexRow = 0;
        }
        if (size == 0) {
            damInfo.setLine(0);
            damInfo.setTop(10);
            return damInfo;
        }
        //遍历最小的
        int line = 0;
        int dex = 0;
        for (int i = 0; i < maxLine; i++) {
            Integer integer = dexList.get(i);
            if (integer > dex) {
                dex = integer;
                line = i;
            }
        }
        Log.e("动画", "line=" + line + " dex=" + dex + "size=" + dexList.size()
                + " maxSize=" + maxLine);
        damInfo.setTop(line * (itemHeight + 10) + 10);
        if (dex < 20) {
            damInfo.setTop(0);
        }
        if (damInfo.getTop() > (heightView - itemHeight - 10)) {
            damInfo.setTop(0);
        }
        damInfo.setLine(line);
        return damInfo;
    }


    private SpannableStringBuilder getRamRadiusStringBuilder(String text
            , int colorStart, int colorCenter, int colorEnd) {
        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
        LinearGradientFontSpan linearGradientFontSpan
                = new LinearGradientFontSpan(colorStart, colorCenter, colorEnd);
        spannableStringBuilder.setSpan(linearGradientFontSpan, 0, spannableStringBuilder.length()
                , Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        return spannableStringBuilder;
    }
}
